package edu.zjucst.spb.service.impl;

import cn.hutool.core.util.IdUtil;
import edu.zjucst.spb.service.FlowableService;
import liquibase.pro.packaged.S;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.IdentityService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.identitylink.api.IdentityLink;
import org.flowable.idm.api.Group;
import org.flowable.idm.api.User;
import org.flowable.idm.engine.impl.persistence.entity.GroupEntityImpl;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author yzl
 **/
@Service
@Slf4j
public class FlowableServiceImpl implements FlowableService {
    @Autowired
    private IdentityService identityService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RepositoryService repositoryService;

    @Override
    public void completeTask(String taskId, Map<String, Object> taskParam) {
        taskService.complete(taskId, taskParam);
    }

    @Override
    public void deployProcessDefinition(String file, String name) {
        repositoryService.createDeployment().addClasspathResource(file).name(name).deploy();
    }

    @Override
    public void deleteProcessDefinition(String id, boolean cascade) {
        repositoryService.deleteDeployment(id, cascade);
    }

    @Override
    public void startProcessInstance(String processKey, String userId, Map<String, Object> startParam) {
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processKey, userId, startParam);
    }

    @Override
    public List<String> queryProcessInstanceByOriginator(String userId) {
        List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().
            processInstanceBusinessKey(userId).orderByStartTime().asc().list();
        List<String> res = new ArrayList<>();
        for (ProcessInstance processInstance : list) {
            res.add(processInstance.getId());
        }
        return res;
    }

    @Override
    public List<String> queryTaskByUserId(String userId) {
        List<Group> groupList = identityService.createGroupQuery().groupMember(userId).list();
        List<String > groupListId = new ArrayList<>();
        for (Group group : groupList) {
            groupListId.add(group.getId());
        }
        List<Task> list = taskService.createTaskQuery().taskCandidateGroupIn(groupListId).orderByTaskCreateTime().asc().list();
        List<String> res = new ArrayList<>();
        for (Task task : list) {
            res.add(task.getId());
        }
        return res;
    }

    @Override
    public List<String> queryTaskByGroupId(String groupId) {
        List<Task> list = taskService.createTaskQuery().taskCandidateGroup(groupId).orderByTaskCreateTime().asc().list();
        List<String> res = new ArrayList<>();
        for (Task task : list) {
            res.add(task.getId());
        }
        return res;
    }

    @Override
    public List<String> queryTaskByProcessInstanceId(String processInstanceId) {
        List<Task> list = taskService.createTaskQuery().processInstanceId(processInstanceId).orderByTaskCreateTime().asc().list();
        List<String> res = new ArrayList<>();
        for (Task task : list) {
            res.add(task.getId());
        }
        return res;
    }

    @Override
    public void createIDMUser(String id, String displayName) {
        User user = identityService.newUser(id);
        user.setDisplayName(displayName);
        identityService.saveUser(user);
    }

    @Override
    public void deleteIDMUser(String id){
        identityService.deleteUser(id);
    }

    @Override
    public String createIDMGroup(String groupName) {
        GroupEntityImpl group = new GroupEntityImpl();
        group.setName(groupName);

        String id = String.valueOf(UUID.nameUUIDFromBytes(groupName.getBytes()));
        group.setId(id);
        group.setRevision(0);
        identityService.saveGroup(group);

        return id;
    }

    @Override
    public void deleteIDMGroup(String id){
        identityService.deleteGroup(id);
    }

    @Override
    public void relateIDMUser2Group(String userid, String groupid) {
        User user = identityService.createUserQuery().userId(userid).singleResult();
        Group group = identityService.createGroupQuery().groupId(groupid).singleResult();
        identityService.createMembership(user.getId(), group.getId());
    }

    @Override
    public void unRelateIDMUser2Group(String userid, String groupid) {
        User user = identityService.createUserQuery().userId(userid).singleResult();
        Group group = identityService.createGroupQuery().groupId(groupid).singleResult();
        identityService.deleteMembership(user.getId(), group.getId());
    }

    @Override
    public Object queryVariableValue(String processInstanceId, String variableName) {
        return runtimeService.getVariable(processInstanceId, variableName);
    }

    @Override
    public void setVariableValue(String processInstanceId, String variableName, Object value) {
        runtimeService.setVariable(processInstanceId, variableName, value);
    }

    @Override
    public void addCandidateGroup(String taskId, String groupId) {
        taskService.addCandidateGroup(taskId, groupId);
    }

    @Override
    public void deleteCandidateGroup(String taskId, String groupId) {
        taskService.deleteCandidateGroup(taskId, groupId);
    }

    @Override
    public List<String> queryTaskCandidateGroup(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        List<IdentityLink> identityLinksForTask = taskService.getIdentityLinksForTask(taskId);
        List<String> res = new ArrayList<>();
        for (IdentityLink identityLink : identityLinksForTask) {
            String groupId = identityLink.getGroupId();
            res.add(groupId);
        }
        return res;
    }
}
